Paranoia.List = {}
Paranoia.List.LastWarning = 0;
Paranoia.List.LastKoSWarning = 0;
Paranoia.List.ActiveHostiles = {};
Paranoia.List.IgnoreList = {};
Paranoia.List.NumberOfButtons = 2;
Paranoia.List.ActiveList = nil; --pointer to frame, initialized in Paranoia:Initialize

local Paranoia = Paranoia;

--[[
Button Initialization
]]--

function Paranoia.List.InitializeButtons()
  local i = 2;
  local thisItem;
  
  Paranoia_EnemyListUnit1:ClearAllPoints(); --Anchors the first button to the enemy list.
  Paranoia_EnemyListUnit1:SetPoint("TOPLEFT", "Paranoia_EnemyList", "TOPLEFT", 8, -8);
  Paranoia_EnemyList:SetBackdropBorderColor(255, 255, 255, ParanoiaData.Config.BorderOpacity)
  Paranoia_EnemyList:SetAlpha(ParanoiaData.Config.FrameOpacity)
  Paranoia_EnemyList:SetScale(ParanoiaData.Config.ListScale)
  
  while (i <= Paranoia.List.NumberOfButtons) do --This loops through existing buttons and anchors each one to the button preceding it.
    thisItem = getglobal("Paranoia_EnemyListUnit"..i);
    thisItem:ClearAllPoints();
    thisItem:SetPoint("TOPLEFT", "Paranoia_EnemyListUnit"..(i - 1), "BOTTOMLEFT", 0, 0);
    i = i + 1;
  end
end

function Paranoia.List.InitializeButtonsCombat()
  local i = 2;
  local thisItem;
  
  Paranoia_EnemyListCombatUnit1:ClearAllPoints();
  Paranoia_EnemyListCombatUnit1:SetPoint("TOPLEFT", "Paranoia_EnemyListCombat", "TOPLEFT", 8, -8);
  Paranoia_EnemyListCombat:SetBackdropBorderColor(255, 255, 255, ParanoiaData.Config.BorderOpacity)
  Paranoia_EnemyListCombat:SetAlpha(ParanoiaData.Config.FrameOpacity)
  Paranoia_EnemyListCombat:SetScale(ParanoiaData.Config.ListScale)
  
  while (i <= Paranoia.List.NumberOfButtons) do
    thisItem = getglobal("Paranoia_EnemyListCombatUnit"..i);
    thisItem:ClearAllPoints();
    thisItem:SetPoint("TOPLEFT", "Paranoia_EnemyListCombatUnit"..(i - 1), "BOTTOMLEFT", 0, 0);
    i = i + 1;
  end
end

--[[
Detection
]]--

function Paranoia.List.ScanCombatEvent(event, sourceName, sourceFlags, destName, destFlags, spellID, spellName) --arg2, arg4, arg5, arg7, arg8, arg9, arg10
  local hostileSource;
  local hostileDest;
  local guessClass;
  local guessLevel;
  local knownSkill;
  local find = string.find;
  
  if Paranoia.DebugEnabled and Paranoia.VerboseEnabled then Paranoia:DMsg(tostring(arg2).." \n|cFFFFFFFFSourceName:|r "..tostring(arg4).." \n|cFFFFFFFFSourceFlags:|r "..tostring(arg5).." \n|cFFFFFFFFDestName:|r "..tostring(arg7).." \n|cFFFFFFFFDestFlags:|r "..tostring(arg8).." \n|cFFFFFFFFSpell:|r "..tostring(arg9).." ("..tostring(arg10)..")"); end
  
  if bit.band(sourceFlags, PEPA_HOSTILEUNITFLAG) == PEPA_HOSTILEUNITFLAG then
    Paranoia:DMsg("***Source unit is hostile.");
    hostileSource = true;
  end
  if bit.band(destFlags, PEPA_HOSTILEUNITFLAG) == PEPA_HOSTILEUNITFLAG then
    Paranoia:DMsg("***Destination unit is hostile.");
    hostileDest = true;
  end
  
  if hostileSource then
    if Paranoia_SpellList == nil then
      Paranoia:DMsg("PEPA spell list is not in memory, loading.");
      Paranoia.List.LastWarning = GetTime();
      Paranoia:LoadSpellList();
    end
    if destName == UnitName("player") then
      Paranoia.List.LastDamagerTime = GetTime();
      Paranoia.List.LastDamager = sourceName;
    end
    if find(event, "RANGE_") or find(event, "SPELL_") or find(event, "SPELL_PERIODIC") then
      local SpellList = Paranoia_SpellList;
      if SpellList[spellID] ~= nil then
        guessClass = SpellList[spellID].Class;
        guessLevel = SpellList[spellID].Level;
        knownSkill = true;
      else
        guessClass = UNKNOWN;
        guessLevel = 0;
        knownSkill = false;
      end
    else
      guessClass = UNKNOWN;
      guessLevel = 0;
      knownSkill = false;
    end
    Paranoia.List.ProcessHostile(sourceName, guessClass, guessLevel, false, 0);
  end
  
  if hostileDest then
    if event == "PARTY_KILL" and sourceName == UnitName("player") then
      Paranoia:incrementKill(arg7);
      Paranoia:DMsg("Player has killed hostile "..arg7..". Incrementing kill count.");
    end
      guessClass = UNKNOWN;
      guessLevel = 0;
      knownSkill = false;
    Paranoia.List.ProcessHostile(destName, guessClass, guessLevel, false, 0);
  end
end

function Paranoia.List.ScanMouseoverTarget(source)
  if UnitIsPlayer(source) and not UnitIsFriend("player", source) then
    local guildName, _, _ = GetGuildInfo(source);
    local name = UnitName(source);
    local _, class = UnitClass(source);
    local level = UnitLevel(source);
    local isLevelKnown = false;
    if level == -1 or level == 0 then isLevelKnown = false; else isLevelKnown = true; end
    if level == -1 then level = UnitLevel("player") + 10; end
    Paranoia.List.ProcessHostile(name, class, level, isLevelKnown, 1, guildName);
  elseif UnitIsPlayer(source) then
    Paranoia.List.AddToIgnore(UnitName(source));
  end
end

--[[
Hostile Handling
]]--

function Paranoia.List.ProcessHostile(name, class, level, levelknown, source, guild, sender, temp) --source: 0 = CL event, 1 = mouseover/target, 2 = party, 3 = guild, 4 = global
  if source == -1 or source == 4 then temp = true; end
  assert(name, "ProcessHostile: Name assertion failed.");
  assert(class, "ProcessHostile: Class assertion failed.");
  assert(tonumber(level), "ProcessHostile: Level assertion failed.");
  if not guild then guild = ""; end

  if Paranoia.DebugEnabled then Paranoia:DMsg("Processing hostile unit: (source "..source.."\n"..name..", "..level.." "..class); end
  
  if Paranoia.List.IgnoreList[name] and not Paranoia:IsPlayerInFFA() then
    Paranoia.List.IgnoreList[name] = GetTime();
    return;
  end
  
  if Paranoia:PlayerExists(name) then
    local dbClass, dbLevel, dbGuild = Paranoia:GetPlayerClassLevelGuild(name);
    if dbClass == UNKNOWN and class ~= UNKNOWN then dbClass = class; end
    if dbLevel < level then dbLevel = level; end
    if dbGuild ~= guild and guild ~= "" then dbGuild = guild; end
    Paranoia:UpdatePlayer(name, dbLevel, dbClass, dbGuild);
  else
    Paranoia:CreateNewPlayer(name, level, class, guild, GetTime(), false, temp);
    if Paranoia.DebugEnabled then Paranoia:DMsg("Created new database entry for player "..name.."."); end
  end
  
  if not Paranoia.List.ActiveHostiles[name] then
    Paranoia.List.AddNewHostile(name, levelknown);
  else
    Paranoia.List.UpdateHostile(name, levelknown);
  end
  
  if GetTime() - Paranoia.List.ActiveHostiles[name].LastComm > 6 and not sender then 
    Paranoia.Comm.SendPlayer(name); 
    Paranoia.List.ActiveHostiles[name].LastComm = GetTime();
  end

  Paranoia.List.Warn(name, source, sender);
end

function Paranoia.List.AddNewHostile(name, levelknown)
  local posX, posY = GetPlayerMapPosition("player");
  posX=floor(posX * 100);
  posY=floor(posY * 100);
  
  Paranoia.List.ActiveHostiles[name] = {
    Time = GetTime(),
    LastComm = GetTime(),
    LevelKnown = levelknown,
    x = posX,
    y = posY,
    Zone = GetMinimapZoneText(),
  };
  if Paranoia.DebugEnabled then Paranoia:DMsg("Added player "..name.." to ActiveHostiles table."); end
end

function Paranoia.List.UpdateHostile(name, levelknown)
  local posX, posY = GetPlayerMapPosition("player");  --update positioning
  posX=floor(posX *100);
  posY=floor(posY *100);
  
  if not levelknown and Paranoia.List.ActiveHostiles[name].LevelKnown then levelknown = true; end
  
  Paranoia.List.ActiveHostiles[name].Time = GetTime();
  Paranoia.List.ActiveHostiles[name].LastComm = GetTime();
  Paranoia.List.ActiveHostiles[name].LevelKnown = levelknown;
  Paranoia.List.ActiveHostiles[name].x = posX;
  Paranoia.List.ActiveHostiles[name].y = posY;
  Paranoia.List.ActiveHostiles[name].Zone = GetMinimapZoneText();
  
  if Paranoia.DebugEnabled then Paranoia:DMsg("Updated player "..name.."'s entry in ActiveHostiles table."); end
end


function Paranoia.List.Warn(name, source, sender)
  local kos = Paranoia:GetPlayerKoS(name);

  if kos and GetTime() - Paranoia.List.LastKoSWarning > ParanoiaData.Config.WarnTimeout then
    Paranoia.List.LastKoSWarning = GetTime()
    if ParanoiaData.Config.SoundEnabled then
      PlaySoundFile("Sound\\Spells\\ShadowWard.wav");
    end
    
    if ParanoiaData.Config.WarnPopupEnabled and not Paranoia.Config.IsConfigOpen then
      Paranoia_KoSPopup:AddMessage("Kill-on-Sight!\n"..name, 0.7,0,0); 
      UIFrameFlash(Paranoia_KoSPopup, 0.4, 0.4, 6, true, 0, 0.3)
    end
  end
  
  if GetTime() - Paranoia.List.LastWarning > ParanoiaData.Config.WarnTimeout then
    Paranoia.List.LastWarning = GetTime();
    if ParanoiaData.Config.SoundEnabled then
      PlaySoundFile("Sound\\Spells\\PVPWarningAlliance.wav");
    end
    
    if ParanoiaData.Config.WarnPopupEnabled and not Paranoia.Config.IsConfigOpen then
      class, _, _ = Paranoia:GetPlayerClassLevelGuild(name);
      if class == UNKNOWN then
        if source == 2 then
          Paranoia_WarnPopup:AddMessage(string.format(PARANOIA_PARTYALERTNOCLASS, sender, name, Paranoia.List.ActiveHostiles[name].x, Paranoia.List.ActiveHostiles[name].y), 255, 0, 0, 1, ParanoiaData.Config.WarnPopupDisplayDuration); 
        elseif source == 3 then
          Paranoia_WarnPopup:AddMessage(string.format(PARANOIA_GUILDALERTNOCLASS, sender, name, Paranoia.List.ActiveHostiles[name].x, Paranoia.List.ActiveHostiles[name].y), 255, 0, 0, 1, ParanoiaData.Config.WarnPopupDisplayDuration); 
        else
          Paranoia_WarnPopup:AddMessage(string.format(PARANOIA_ALERTNOCLASS, Paranoia.OppFaction, name), 255, 0, 0, 1, ParanoiaData.Config.WarnPopupDisplayDuration); 
        end
      else
        if source == 2 then 
          Paranoia_WarnPopup:AddMessage(string.format(PARANOIA_PARTYALERTCLASS, sender, Paranoia:LocalizeClass(class), name, Paranoia.List.ActiveHostiles[name].x, Paranoia.List.ActiveHostiles[name].y), 255, 0, 0, 1, ParanoiaData.Config.WarnPopupDisplayDuration); 
        elseif source == 3 then
          Paranoia_WarnPopup:AddMessage(string.format(PARANOIA_GUILDALERTCLASS, sender, Paranoia:LocalizeClass(class), name, Paranoia.List.ActiveHostiles[name].x, Paranoia.List.ActiveHostiles[name].y), 255, 0, 0, 1, ParanoiaData.Config.WarnPopupDisplayDuration); 
        else
          Paranoia_WarnPopup:AddMessage(string.format(PARANOIA_ALERTCLASSKNOWN, Paranoia.OppFaction, Paranoia:LocalizeClass(class), name), 255, 0, 0, 1, ParanoiaData.Config.WarnPopupDisplayDuration); 
        end
      end
    end
  end
end

--[[
Enemylist Visual Update
]]--

function Paranoia.List.UpdateHostileList()
  local button, buttonFrame, buttonText;
  local listWidth, displayedHostiles = 0, 0;
  local displayName, displayClass, displayLevel, englishClass, numericLevel;
  local ActiveHostiles = Paranoia.List.ActiveHostiles;
  local framePrefix;
  local colorA, colorR, colorG, colorB = 0, 0, 0, 0;
  local i = 1;
  
  if InCombatLockdown() then
    framePrefix = "Paranoia_EnemyListCombatUnit"; 
  else 
    framePrefix = "Paranoia_EnemyListUnit";
  end
  
  for i, name in ipairs(Paranoia.List.SortHostileList()) do --loop through hostilelist (in order)
    if ActiveHostiles[name].Time < GetTime() - ParanoiaData.Config.ListTimeout then --this unit has expired.
      ActiveHostiles[name] = nil;
    elseif i <= ParanoiaData.Config.MaxHostiles then
      if i > Paranoia.List.NumberOfButtons then Paranoia.List.CreateNewButton(); end
      buttonFrame = getglobal(framePrefix..i);
      buttonText = getglobal(framePrefix..i.."Text");
      button = getglobal(framePrefix..i.."Button");
      
      englishClass, numericLevel, _ = Paranoia:GetPlayerClassLevelGuild(name)
      displayClass = Paranoia:LocalizeClass(englishClass);
      displayLevel = Paranoia.List.StringLevel(numericLevel, ActiveHostiles[name].LevelKnown);
      englishClass = string.upper(englishClass); --fix me later
      
      if ParanoiaData.Config.FadeInactive then 
        colorA = 1 - (Paranoia:Round(GetTime() - ActiveHostiles[name].Time, 3) / ParanoiaData.Config.ListTimeout); 
      else 
        colorA = 1; 
      end
      
      if button.IsMouseOver then colorA = 1; end
      
      if (englishClass == "DEATHKNIGHT") then colorR = RAID_CLASS_COLORS["DEATHKNIGHT"].r; colorG = RAID_CLASS_COLORS["DEATHKNIGHT"].g; colorB = RAID_CLASS_COLORS["DEATHKNIGHT"].b;
      elseif (englishClass == "DRUID") then colorR = RAID_CLASS_COLORS["DRUID"].r; colorG = RAID_CLASS_COLORS["DRUID"].g; colorB = RAID_CLASS_COLORS["DRUID"].b;
      elseif (englishClass == "HUNTER") then colorR = RAID_CLASS_COLORS["HUNTER"].r; colorG = RAID_CLASS_COLORS["HUNTER"].g; colorB = RAID_CLASS_COLORS["HUNTER"].b;
      elseif (englishClass == "MAGE") then colorR = RAID_CLASS_COLORS["MAGE"].r; colorG = RAID_CLASS_COLORS["MAGE"].g; colorB = RAID_CLASS_COLORS["MAGE"].b;
      elseif (englishClass == "PALADIN") then colorR = RAID_CLASS_COLORS["PALADIN"].r; colorG = RAID_CLASS_COLORS["PALADIN"].g; colorB = RAID_CLASS_COLORS["PALADIN"].b;
      elseif (englishClass == "PRIEST") then colorR = RAID_CLASS_COLORS["PRIEST"].r; colorG = RAID_CLASS_COLORS["PRIEST"].g; colorB = RAID_CLASS_COLORS["PRIEST"].b;
      elseif (englishClass == "ROGUE") then colorR = RAID_CLASS_COLORS["ROGUE"].r; colorG = RAID_CLASS_COLORS["ROGUE"].g; colorB = RAID_CLASS_COLORS["ROGUE"].b;
      elseif (englishClass == "SHAMAN") then colorR = RAID_CLASS_COLORS["SHAMAN"].r; colorG = RAID_CLASS_COLORS["SHAMAN"].g; colorB = RAID_CLASS_COLORS["SHAMAN"].b;
      elseif (englishClass == "WARLOCK") then colorR = RAID_CLASS_COLORS["WARLOCK"].r; colorG = RAID_CLASS_COLORS["WARLOCK"].g; colorB = RAID_CLASS_COLORS["WARLOCK"].b;
      elseif (englishClass == "WARRIOR") then colorR = RAID_CLASS_COLORS["WARRIOR"].r; colorG = RAID_CLASS_COLORS["WARRIOR"].g; colorB = RAID_CLASS_COLORS["WARRIOR"].b;
      else colorR = 0.6; colorG = 0.6; colorB =0.6; end
      
      buttonText:SetText(name.." ("..displayClass.."/"..displayLevel..")");
      buttonText:SetTextColor(colorR, colorG, colorB, colorA);
      
      if buttonText:GetStringWidth() + 20 > listWidth then listWidth = buttonText:GetStringWidth() + 20; end
      buttonFrame:SetWidth(buttonText:GetStringWidth()+10);
      buttonText:SetWidth(buttonText:GetStringWidth()+10);
      buttonFrame:Show();
      button.nickname = name;
      button.id = name;
      
      i = i + 1;
      displayedHostiles = displayedHostiles + 1;
    end
  end
 
  Paranoia.List.ActiveList:SetWidth(listWidth);
  
  if (displayedHostiles == 0) then
    local button1 = getglobal(framePrefix.."1Text")
    local button2 = getglobal(framePrefix.."2Text")
    displayedHostiles = 2;
    if string.find(PARANOIA_NODETECTL1, "%s", 1, true) ~= nil then  --(since %s is a lua regex character we must specify plain matching)
      button1:SetText(string.format(PARANOIA_NODETECTL1, Paranoia.OppFaction));
      button2:SetText(PARANOIA_NODETECTL2);
    else
      button1:SetText(PARANOIA_NODETECTL1);
      button2:SetText(string.format(PARANOIA_NODETECTL2, Paranoia.OppFaction));
    end
      button1:SetTextColor(0.5, 0.5, 0.5);
      button2:SetTextColor(0.5, 0.5, 0.5);
      if button1:GetStringWidth() < button2:GetStringWidth() then Paranoia.List.ActiveList:SetWidth(button2:GetStringWidth() + 22);
    end
  end
  
  i = displayedHostiles + 1;
  
  while i <= Paranoia.List.NumberOfButtons do
    buttonFrame = getglobal(framePrefix..i);
    buttonText = getglobal(framePrefix..i.."Text");
    button = getglobal(framePrefix..i.."Button");
    if i > 2 then buttonFrame:Hide(); end
    button.nickname = "emptyButton"..i;
    button.id = "emptyid"..i; 
    buttonText:SetText("");
    buttonText:SetTextColor(0.5, 0.5, 0.5);
    i = i + 1;
  end
    
  if (displayedHostiles < 2) then displayedHostiles = 2; end

  Paranoia.List.ActiveList:SetHeight(10 + displayedHostiles * 18); 
end

local orderedHostiles = {}
--[[doesn't actually SORT the table, but returns an array with alphabetized names.
Note that I am doing a regular for i loop instead of using an iterator because ipairs
seems to skip duplicate values, which caused issues and left items in the table.
]]--
function Paranoia.List.SortHostileList() 
    for i = 1, #orderedHostiles do table.remove(orderedHostiles, i); end 
    for name in pairs(Paranoia.List.ActiveHostiles) do table.insert(orderedHostiles, name); end
    table.sort(orderedHostiles)
    return orderedHostiles;
end

function Paranoia.List.StringLevel(level, levelknown)
  if level == 80 then return "80"; end
  if level ~= 0 and levelknown then return tostring(level); end
  if level ~= 0 and not levelknown then return tostring(level).."+"; end
  if level == 0 then return "?"; end
end

--[[
Miscellaneous
]]--

function Paranoia.List.UpdateVisibility()
  if not ParanoiaData.Config.Enabled then Paranoia.List.HideList(true); return; end
  if ParanoiaData.Config.DisableInBG and Paranoia:IsPlayerInBG() then Paranoia.List.HideList(true); return; end
  if ParanoiaData.Config.DisableInArena and Paranoia:IsPlayerInArena() then Paranoia.List.HideList(true); return; end
  if ParanoiaData.Config.DisableInFFA and Paranoia:IsPlayerInFFA() then Paranoia.List.HideList(true); return; end
  if ParanoiaData.Config.DisableInSanctuaries and Paranoia:IsPlayerInSanctuary() then Paranoia.List.HideList(true); return; end
  if ParanoiaData.Config.HideList then Paranoia.List.HideList(false); return; end
  if Paranoia.List.ActiveList:GetAlpha() == 0 then Paranoia.List.ShowList(); end
end

function Paranoia.List.ShowList()
  if InCombatLockdown() then Paranoia.List.ActiveList = Paranoia_EnemyListCombat; else Paranoia.List.ActiveList = Paranoia_EnemyList; end
  Paranoia.List.ActiveList:Show();
  UIFrameFadeIn(Paranoia.List.ActiveList, 0.2, 0, ParanoiaData.Config.FrameOpacity);
  Paranoia.Hidden = false;
  Paranoia.List.Enable();
end

function Paranoia.List.HideList(disable)  --if true is passed to HideList Paranoia will disable itself.
  if InCombatLockdown() then Paranoia.List.ActiveList = Paranoia_EnemyListCombat; else Paranoia.List.ActiveList = Paranoia_EnemyList; end
  if Paranoia:Round(Paranoia.List.ActiveList:GetAlpha(), 2) == Paranoia:Round(ParanoiaData.Config.FrameOpacity, 2) then
    Paranoia.FramesWaitingToClose[Paranoia.List.ActiveList:GetName()] = GetTime();
    UIFrameFadeOut(Paranoia.List.ActiveList, 0.2, ParanoiaData.Config.FrameOpacity, 0);
    Paranoia.Hidden = true;
  end
  if disable then Paranoia.List.Disable(); end
end

function Paranoia.List.Disable()
  if not Paranoia.Enabled then return; end
  Paranoia.Enabled = false;
  Paranoia.UnregisterEvents();
end

function Paranoia.List.Enable()
  Paranoia.Enabled = true;
  Paranoia.RegisterEvents();
end

function Paranoia.List.CreateNewButton(parent)
  Paranoia.List.NumberOfButtons = Paranoia.List.NumberOfButtons + 1;
  local newbutton = CreateFrame("Button", "Paranoia_EnemyListUnit"..tostring(Paranoia.List.NumberOfButtons), Paranoia_EnemyList, "Paranoia_EnemyListUnitTemplate");
  newbutton:ClearAllPoints();
  newbutton:SetPoint("TOPLEFT", "Paranoia_EnemyListUnit"..tostring(Paranoia.List.NumberOfButtons - 1), "BOTTOMLEFT", 0, 0);
  local newbuttoncombat = CreateFrame("Button", "Paranoia_EnemyListCombatUnit"..tostring(Paranoia.List.NumberOfButtons), Paranoia_EnemyListCombat, "Paranoia_EnemyListCombatUnitTemplate");
  newbuttoncombat:ClearAllPoints();
  newbuttoncombat:SetPoint("TOPLEFT", "Paranoia_EnemyListCombatUnit"..tostring(Paranoia.List.NumberOfButtons - 1), "BOTTOMLEFT", 0, 0);
end

local listAnchor, listOffsetX, listOffsetY;
function Paranoia.List.EnteringCombat()
  Paranoia.List.ActiveList = Paranoia_EnemyListCombat;
  Paranoia_EnemyList:StopMovingOrSizing();
  listAnchor, _, _, listOffsetX, listOffsetY = Paranoia_EnemyList:GetPoint(1)
  Paranoia_EnemyListCombat:ClearAllPoints();
  Paranoia_EnemyListCombat:SetPoint(listAnchor, listOffsetX, listOffsetY);
  Paranoia_EnemyListCombat:SetUserPlaced(true);
  Paranoia_EnemyList:Hide()
  Paranoia_EnemyListCombat:Show()
end

function Paranoia.List.LeavingCombat()
  Paranoia.List.ActiveList = Paranoia_EnemyList;
  Paranoia_EnemyListCombat:StopMovingOrSizing();
  listAnchor, _, _, listOffsetX, listOffsetY = Paranoia_EnemyListCombat:GetPoint(1)
  Paranoia_EnemyList:ClearAllPoints();
  Paranoia_EnemyList:SetPoint(listAnchor, listOffsetX, listOffsetY);
  Paranoia_EnemyList:SetUserPlaced(true);
  Paranoia_EnemyListCombat:Hide()
  Paranoia.List.InitializeButtons() --reinitialize button positions incase any new units were added in combat (since this frame is secure they would not have been positioned properly)
  Paranoia_EnemyList:Show()
end

function Paranoia.List.AddToIgnore(name)
  if not Paranoia.List.IgnoreList[name] then Paranoia.List.IgnoreList[name] = GetTime(); end
end

function Paranoia.List.CleanIgnore()
  for name,_ in pairs(Paranoia.List.IgnoreList) do
    if (Paranoia.List.IgnoreList[name] < GetTime() - (60 * 15)) then		-- 3 hours
      Paranoia.List.IgnoreList[name] = nil;
    end
  end
end
    
function Paranoia.List.SetLock(locked)
  local i = 1;
  if (locked) then
    Paranoia_EnemyList:RegisterForDrag();
    Paranoia_EnemyListCombat:RegisterForDrag();
    for i = 1, Paranoia.List.NumberOfButtons do
      button = getglobal("Paranoia_EnemyListUnit"..i);
      button:RegisterForDrag();
    end
    for i = 1, Paranoia.List.NumberOfButtons do
      button = getglobal("Paranoia_EnemyListCombatUnit"..i);
      button:RegisterForDrag();
    end
  else
    Paranoia_EnemyList:RegisterForDrag("LeftButton");
    Paranoia_EnemyListCombat:RegisterForDrag("LeftButton");
    for i = 1, Paranoia.List.NumberOfButtons do
      button = getglobal("Paranoia_EnemyListUnit"..i);
      button:RegisterForDrag("LeftButton");
    end
    for i = 1, Paranoia.List.NumberOfButtons do
      button = getglobal("Paranoia_EnemyListCombatUnit"..i);
      button:RegisterForDrag("LeftButton");
    end
  end
end